{ "cells": [ { "cell_type": "markdown", "id": "dcd6670a", "metadata": {}, "source": [ "# Enabling Your GPU for a Solver in MUSICA\n", "\n", "This tutorial will show you to use utilize a GPU for your MUSICA work.
\n", "However, this tutorial will not cover how to efficiently use a GPU through parallelization; it will simply introduce getting a GPU set up to run your code.
\n", "Note: This tutorial requires you to have a Linux GPU-ready environment handy, such as a supercomputing node; it will fail otherwise." ] }, { "cell_type": "markdown", "id": "0e934c67", "metadata": {}, "source": [ "## 1. Creating a GPU Virtual Environment\n", "\n", "Running code on a GPU requires a different install protocol when setting up a virtual environment.
\n", "To do so, run these commands in your terminal:\n", "\n", "```\n", "conda create --name musica_gpu python=3.9\n", "conda activate musica_gpu\n", "pip install --upgrade setuptools pip wheel\n", "pip install nvidia-pyindex\n", "pip install musica[gpu]\n", "conda install ipykernel scikit-learn seaborn scipy dask\n", "```" ] }, { "cell_type": "markdown", "id": "2cd76107", "metadata": {}, "source": [ "## 2. Importing MUSICA\n", "\n", "Importing MUSICA is largerly the same, but with an additional is_cuda_available() function to verify that the GPU is running properly:" ] }, { "cell_type": "code", "execution_count": null, "id": "0fe92903", "metadata": {}, "outputs": [], "source": [ "import musica\n", "import musica.mechanism_configuration as mc\n", "import matplotlib.pyplot as plt\n", "from scipy.stats import qmc\n", "import pandas as pd\n", "import numpy as np\n", "import seaborn as sns\n", "from musica.cuda import is_cuda_available" ] }, { "cell_type": "markdown", "id": "27039537", "metadata": {}, "source": [ "As with creating the music_box environment in MusicBox's [Basic Workflow Tutorial](https://ncar.github.io/music-box/branch/main/tutorials/1.%20basic_workflow.html), this cell may be slow to run the first time." ] }, { "cell_type": "markdown", "id": "9d82609a", "metadata": {}, "source": [ "## 3. Running a Basic Solver on GPU\n", "\n", "This code is a copy of the [Hypercube Tutorial](2.%20hypercube.ipynb), but with an if statement added outside the main code to verify that it is running on a GPU.
\n", "If you are seeing \"Error: No GPU Available\" being printed, that means a GPU was not detected; verify that your environment has a GPU." ] }, { "cell_type": "code", "execution_count": 1, "id": "54dc9c1b", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'is_cuda_available' is not defined", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mNameError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[43mis_cuda_available\u001b[49m():\n\u001b[32m 2\u001b[39m A = mc.Species(name=\u001b[33m\"\u001b[39m\u001b[33mA\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m B = mc.Species(name=\u001b[33m\"\u001b[39m\u001b[33mB\u001b[39m\u001b[33m\"\u001b[39m)\n", "\u001b[31mNameError\u001b[39m: name 'is_cuda_available' is not defined" ] } ], "source": [ "if is_cuda_available():\n", " A = mc.Species(name=\"A\")\n", " B = mc.Species(name=\"B\")\n", " C = mc.Species(name=\"C\")\n", " species = [A, B, C]\n", " gas = mc.Phase(name=\"gas\", species=species)\n", "\n", " r1 = mc.Arrhenius(\n", " name=\"A_to_B\",\n", " A=4.0e-3, # Pre-exponential factor\n", " C=50, # Activation energy (units assumed to be K)\n", " reactants=[A],\n", " products=[B],\n", " gas_phase=gas\n", " )\n", "\n", " r2 = mc.Arrhenius(\n", " name=\"B_to_C\",\n", " A=4.0e-3,\n", " C=50,\n", " reactants=[B],\n", " products=[C],\n", " gas_phase=gas\n", " )\n", "\n", " mechanism = mc.Mechanism(\n", " name=\"musica_micm_example\",\n", " species=species,\n", " phases=[gas],\n", " reactions=[r1, r2]\n", " )\n", "\n", " solver = musica.MICM(mechanism = mechanism, solver_type = musica.SolverType.cuda_rosenbrock)\n", "\n", " num_grid_cells = 100\n", " state = solver.create_state(num_grid_cells)\n", "\n", " ndim = 5\n", " nsamples = num_grid_cells\n", "\n", " # Create a Latin Hypercube sampler in the unit hypercube\n", " sampler = qmc.LatinHypercube(d=ndim)\n", "\n", " # Generate samples\n", " sample = sampler.random(n=nsamples)\n", "\n", " # Define bounds for each dimension\n", " l_bounds = [275, 100753.3, 0, 0, 0] # Lower bounds\n", " u_bounds = [325, 101753.3, 10, 10, 10] # Upper bounds\n", "\n", " # Scale the samples to the defined bounds\n", " sample_scaled = qmc.scale(sample, l_bounds, u_bounds)\n", "\n", " temperatures = sample_scaled[:, 0]\n", " pressures = sample_scaled[:, 1]\n", " concentrations = {\n", " \"A\": [],\n", " \"B\": [],\n", " \"C\": []\n", " }\n", " concentrations[\"A\"] = sample_scaled[:, 2]\n", " concentrations[\"B\"] = sample_scaled[:, 3]\n", " concentrations[\"C\"] = sample_scaled[:, 4]\n", "\n", " state.set_conditions(temperatures, pressures)\n", " state.set_concentrations(concentrations)\n", " concentrations_solved = []\n", " time_step_length = 1\n", " sim_length = 60\n", " curr_time = 0\n", "\n", " while curr_time <= sim_length:\n", " solver.solve(state, curr_time)\n", " concentrations_solved.append(state.get_concentrations())\n", " curr_time += time_step_length\n", "\n", " def convert_results_all_cells():\n", " concentrations_solved_pd = []\n", " time = []\n", " for i in range(0, sim_length + 1, time_step_length):\n", " for j in range(0, num_grid_cells):\n", " concentrations_solved_pd.append({species: concentration[j] for species, concentration in concentrations_solved[int(i/time_step_length)].items()})\n", " time.append(i)\n", " df = pd.DataFrame(concentrations_solved_pd)\n", " df = df.rename(columns = {'A' : 'CONC.A.mol m-3', 'B' : 'CONC.B.mol m-3', 'C' : 'CONC.C.mol m-3'})\n", " df['time.s'] = time\n", " df['ENV.temperature.K'] = np.repeat(temperatures[0], (sim_length/time_step_length + 1.0) * num_grid_cells)\n", " df['ENV.pressure.Pa'] = np.repeat(pressures[0], (sim_length/time_step_length + 1.0) * num_grid_cells)\n", " df['ENV.air number density.mol m-3'] = np.repeat(state.get_conditions()['air_density'][0], (sim_length/time_step_length + 1.0) * num_grid_cells)\n", " df = df[['time.s', 'ENV.temperature.K', 'ENV.pressure.Pa', 'ENV.air number density.mol m-3', 'CONC.A.mol m-3', 'CONC.B.mol m-3', 'CONC.C.mol m-3']]\n", " return concentrations_solved_pd, df\n", "\n", " concentrations_solved_pd, df = convert_results_all_cells()\n", "\n", " sns.lineplot(data=df, x='time.s', y='CONC.A.mol m-3', errorbar=('ci', 95), err_kws={'alpha' : 0.4}, label='CONC.A.mol m-3')\n", " sns.lineplot(data=df, x='time.s', y='CONC.B.mol m-3', errorbar=('ci', 95), err_kws={'alpha' : 0.4}, label='CONC.B.mol m-3')\n", " sns.lineplot(data=df, x='time.s', y='CONC.C.mol m-3', errorbar=('ci', 95), err_kws={'alpha' : 0.4}, label='CONC.C.mol m-3')\n", " plt.title('Average concentration with CI over time')\n", " plt.ylabel('Concentration (mol m-3)')\n", " plt.xlabel('Time (s)')\n", " plt.legend(loc='center right')\n", " plt.show()\n", "\n", " min_y = []\n", " max_y = []\n", " for i in range(0, sim_length + 1, time_step_length):\n", " min_y.append({species: np.min(concentration) for species, concentration in concentrations_solved[int(i/time_step_length)].items()})\n", " max_y.append({species: np.max(concentration) for species, concentration in concentrations_solved[int(i/time_step_length)].items()})\n", " time_x = list(map(float, range(0, sim_length + 1, time_step_length)))\n", "\n", " plt.fill_between(time_x, [y['A'] for y in min_y], [y['A'] for y in max_y], alpha = 0.4, label='CONC.A.mol m-3')\n", " plt.fill_between(time_x, [y['B'] for y in min_y], [y['B'] for y in max_y], alpha = 0.4, label='CONC.B.mol m-3')\n", " plt.fill_between(time_x, [y['C'] for y in min_y], [y['C'] for y in max_y], alpha = 0.4, label='CONC.C.mol m-3')\n", " plt.title('Concentration range over time')\n", " plt.ylabel('Concentration (mol m-3)')\n", " plt.xlabel('Time (s)')\n", " plt.legend()\n", " plt.show()\n", "else:\n", " print(\"Error: No GPU Available\")" ] } ], "metadata": { "kernelspec": { "display_name": "musica", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.10" } }, "nbformat": 4, "nbformat_minor": 5 }